from django.db import models
from django.utils import timezone
from cryptography.fernet import Fernet
from django.conf import settings
import base64


class City(models.Model):
    """城市模型"""
    name = models.CharField(max_length=100, verbose_name='城市名称', unique=True)
    code = models.CharField(max_length=20, verbose_name='城市代码', unique=True)
    description = models.TextField(blank=True, verbose_name='城市描述')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        verbose_name = '城市'
        verbose_name_plural = '城市'
        ordering = ['name']

    def __str__(self):
        return self.name


class DataCenter(models.Model):
    """机房模型"""
    name = models.CharField(max_length=100, verbose_name='机房名称')
    city = models.ForeignKey(City, on_delete=models.CASCADE, verbose_name='所属城市')
    address = models.TextField(verbose_name='机房地址')
    description = models.TextField(blank=True, verbose_name='机房描述')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        verbose_name = '机房'
        verbose_name_plural = '机房'
        ordering = ['city', 'name']
        unique_together = ['name', 'city']

    def __str__(self):
        return f"{self.city.name}-{self.name}"


class Host(models.Model):
    """主机模型"""
    STATUS_CHOICES = [
        ('online', '在线'),
        ('offline', '离线'),
        ('maintenance', '维护中'),
        ('decommissioned', '已下线'),
    ]
    
    OS_CHOICES = [
        ('linux', 'Linux'),
        ('windows', 'Windows'),
        ('macos', 'macOS'),
        ('other', '其他'),
    ]

    hostname = models.CharField(max_length=100, verbose_name='主机名', unique=True)
    ip_address = models.GenericIPAddressField(verbose_name='IP地址', unique=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='offline', verbose_name='状态')
    os_type = models.CharField(max_length=20, choices=OS_CHOICES, default='linux', verbose_name='操作系统')
    cpu_cores = models.IntegerField(default=1, verbose_name='CPU核心数')
    memory_gb = models.IntegerField(default=1, verbose_name='内存(GB)')
    disk_gb = models.IntegerField(default=10, verbose_name='磁盘(GB)')
    data_center = models.ForeignKey(DataCenter, on_delete=models.CASCADE, verbose_name='所属机房')
    description = models.TextField(blank=True, verbose_name='主机描述')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    last_ping_time = models.DateTimeField(null=True, blank=True, verbose_name='最后ping时间')
    last_ping_status = models.BooleanField(default=False, verbose_name='最后ping状态')

    class Meta:
        verbose_name = '主机'
        verbose_name_plural = '主机'
        ordering = ['data_center', 'hostname']

    def __str__(self):
        return f"{self.hostname} ({self.ip_address})"


class HostPassword(models.Model):
    """主机密码模型（加密存储）"""
    host = models.OneToOneField(Host, on_delete=models.CASCADE, verbose_name='主机')
    encrypted_password = models.TextField(verbose_name='加密后的密码')
    password_changed_at = models.DateTimeField(auto_now_add=True, verbose_name='密码修改时间')
    next_change_time = models.DateTimeField(verbose_name='下次修改时间', default=timezone.now)
    password_history = models.JSONField(default=list, verbose_name='密码历史记录')
    max_password_history = models.IntegerField(default=5, verbose_name='最大密码历史记录数')
    
    class Meta:
        verbose_name = '主机密码'
        verbose_name_plural = '主机密码'

    def __str__(self):
        return f"{self.host.hostname} 密码"

    def set_password(self, plain_password):
        """设置加密密码"""
        from cryptography.fernet import Fernet
        import base64
        from django.conf import settings
        from django.utils import timezone
        
        # 检查密码是否在历史记录中
        if self.is_password_in_history(plain_password):
            raise ValueError("新密码不能与最近使用的密码相同")
        
        fernet = Fernet(settings.ENCRYPTION_KEY.encode())
        encrypted = fernet.encrypt(plain_password.encode())
        self.encrypted_password = base64.b64encode(encrypted).decode()
        
        # 添加到密码历史记录
        self.add_to_password_history(plain_password)
        
        self.password_changed_at = timezone.now()
        self.next_change_time = timezone.now() + timezone.timedelta(hours=8)
        self.save()

    def get_password(self):
        """获取解密后的密码"""
        try:
            from cryptography.fernet import Fernet
            import base64
            from django.conf import settings
            
            fernet = Fernet(settings.ENCRYPTION_KEY.encode())
            encrypted = base64.b64decode(self.encrypted_password.encode())
            return fernet.decrypt(encrypted).decode()
        except Exception:
            return None

    def is_password_expired(self):
        """检查密码是否过期"""
        from django.utils import timezone
        return timezone.now() >= self.next_change_time

    def add_to_password_history(self, plain_password):
        """添加密码到历史记录"""
        from cryptography.fernet import Fernet
        import base64
        from django.conf import settings
        
        fernet = Fernet(settings.ENCRYPTION_KEY.encode())
        encrypted = fernet.encrypt(plain_password.encode())
        encrypted_history = base64.b64encode(encrypted).decode()
        
        # 添加新密码到历史记录开头
        self.password_history.insert(0, {
            'encrypted_password': encrypted_history,
            'changed_at': timezone.now().isoformat()
        })
        
        # 保持历史记录数量限制
        if len(self.password_history) > self.max_password_history:
            self.password_history = self.password_history[:self.max_password_history]

    def is_password_in_history(self, plain_password):
        """检查密码是否在历史记录中"""
        from cryptography.fernet import Fernet
        import base64
        from django.conf import settings
        
        fernet = Fernet(settings.ENCRYPTION_KEY.encode())
        
        for history_item in self.password_history:
            try:
                encrypted = base64.b64decode(history_item['encrypted_password'].encode())
                decrypted = fernet.decrypt(encrypted).decode()
                if decrypted == plain_password:
                    return True
            except Exception:
                continue
        return False

    def get_password_age(self):
        """获取密码年龄（小时）"""
        from django.utils import timezone
        age = timezone.now() - self.password_changed_at
        return age.total_seconds() / 3600


class HostPingLog(models.Model):
    """主机ping日志模型"""
    host = models.ForeignKey(Host, on_delete=models.CASCADE, verbose_name='主机')
    ping_time = models.DateTimeField(auto_now_add=True, verbose_name='ping时间')
    is_reachable = models.BooleanField(verbose_name='是否可达')
    response_time = models.FloatField(null=True, blank=True, verbose_name='响应时间(ms)')
    error_message = models.TextField(blank=True, verbose_name='错误信息')

    class Meta:
        verbose_name = '主机ping日志'
        verbose_name_plural = '主机ping日志'
        ordering = ['-ping_time']

    def __str__(self):
        return f"{self.host.hostname} - {self.ping_time} - {'可达' if self.is_reachable else '不可达'}"
